#pragma once

#include "../../Common/Shas/Shas/Shas.h"
#include "../../Common/ScreenMask/ScreenMask.h"
#include "../../Common/Utilities.h"

#include "../../Common/Interfaces/IPlugin.h"
#include "../../Common/Interfaces/IEnvironment.h"
#include "../../Common/Parameter/Checkbox.h"
#include "../../Common/Parameter/Slider.h"
#include "../../Common/Parameter/EditBox.h"
#include "../../Common/DetourHelper.h"

#include "Texture.h"


struct r_DepthOfField
{
	enum Enumeration
	{
		Depth,
		DepthStep,
		SizeFactor,
		BlurSteps,
		DofStrength,
		ShowDepthOnly,
		ZSizeFactor,
		ZBlurSteps,
		ZScreenMaskCount,
		UseCompareMode
	};
};


class k_Plugin : public k_Direct3D9BasePlugin
{
public:
	k_Plugin(IServiceLocator& ar_ServiceLocator);
	virtual ~k_Plugin();

	virtual void Initialize(IDirect3DDevice9* ar_Device_);
	virtual void Deinitialize();

	virtual void Render();
	virtual void OnBeforeReset();
	virtual void OnAfterReset();

	virtual void set_Active(bool ab_State);

protected:
	bool UpdateParameters();

	LPDIRECT3DTEXTURE9 CreateTexture(int ai_Width, int ai_Height, D3DFORMAT ae_Format);
	IShader* LoadShader(const std::string& as_FileName, const std::string& as_Path="Core");

	void CopyRenderTarget(IDirect3DTexture9* ar_Texture_, RECT* ar_Rect_);

	void Render(IRenderable* ar_ScreenMask_, IShader* ar_Shader_);
	void Blur(int ai_Steps);

	void RebuildTextures();
	void UpdateTextures();
	void UpdateRendering();

	bool CanRender();

	double CalcZDepth(double ad_PercentageDepth);
	bool IsViewportNew();

	void ZBlur(int ai_Steps);

private:
	r_Texture mr_BackBufferTexture;
	r_Texture mr_BlurTexture;

	r_Texture mr_ZBackBufferTexture;
	r_Texture mr_ZBlurTexture;
	ScreenMask* mr_ScreenMask_;
	std::vector<ScreenMask*> mk_ZScreenMaskList;
	BatchScreenMask* mk_ZScreenMaskBatch_;
	ScreenMask* mr_QuarterMask_;
	ScreenMask* mr_ZQuarterMask_;
	ScreenMask* mr_BlurMask_;
	ScreenMask* mr_ZBlurMask_;
	ScreenMask* mr_BlurToScreenMask_;
	ScreenMask* mr_ClearMask_;

	IShaderSystem* mr_ShaderSystem_;
	IShader* mr_ShowTextureShader_;
	IShader* mr_ShowTranslucentTextureShader_;
	IShader* mr_ShowBlurTextureShader_;
	IShader* mr_BlurShader_;
	IShader* mr_ZBlurShader_;
	IShader* mr_DepthRenderShader_;
	IShader* mr_BlackRenderShader_;
	IShader* mr_ShowZTextureShader_;
	IShader* mr_ShowZBlurTextureShader_;
	IShader* mr_DepthOfFieldShader_;

	DWORD mdw_LastTime;

	float mf_Depth;
	float mf_DepthStep;
	float mf_SizeFactor;
	int mi_BlurSteps;
	float mf_DofStrength;
	bool mb_ShowDepthOnly;

	float mf_ZSizeFactor;
	int mi_ZBlurSteps;
	int mi_ZScreenMaskCount;

	bool mb_NeedDepthUpdate;
	bool mb_UseCompareMode;

	IDirect3DStateBlock9* mr_DefaultStateBlock_;
	IDirect3DStateBlock9* mr_CurrentStateBlock_;

	D3DCAPS9 mr_Caps;
	D3DVIEWPORT9 mr_Viewport;

	D3DXMATRIX mr_ViewMatrix;
	D3DXMATRIX mr_ProjMatrix;

	std::wstring ms_LogFile;

	bool mb_NeedToReset;
};


class HelTextureSemanticHandler
	: public ISemanticHandler
{
public:
	HelTextureSemanticHandler(const std::string& as_Name, r_Texture* ar_Texture_)
		: Name(as_Name)
		, mr_Texture_(ar_Texture_)
	{}

	virtual ~HelTextureSemanticHandler()
	{}

	virtual void OnHandle(IShader* inShader, IShaderParameter* inParameter)
	{
		if (inParameter->get_Type() == ShaderParameterType::Texture2D)
		{
			inParameter->set_Texture2D(mr_Texture_->mr_Texture_);
		}
	}

	virtual void OnShaderSystemRefresh(IShader* inShader)
	{}

	virtual const std::string& get_Name() const
	{
		return Name;
	}

protected:
	std::string Name;
	r_Texture* mr_Texture_;
};
